﻿--[[
   @brief    client global tips show frame
   @author   jadonsun
   @version  1.0
   @date     2017-04-18
--]]

client_tips_res = {

    -- normal tips tpf路径
    -- 标题路径
    title_txt = "title_bar\\title_txt";
    title_set = "title_bar\\title_set_btn";
    title_close = "title_bar\\title_close_btn";
    -- 内容区路径
    txt_main_type_father = "tips_content_container\\content_txt\\txt_main_type_c";
    txt_main_type = "tips_content_container\\content_txt\\txt_main_type_c\\txt_main_type";
    txt_main_type_btn = "tips_content_container\\content_txt\\txt_main_type_c\\txt_main_type_b";
    txt_main_type_big = "tips_content_container\\content_txt\\txt_main_type_c\\txt_main_type_big";
    txt_sub_type_father = "tips_content_container\\content_txt\\txt_sub_type_c";
    txt_sub_type = "tips_content_container\\content_txt\\txt_sub_type_c\\txt_sub_type";
    txt_sub_type_btn = "tips_content_container\\content_txt\\txt_sub_type_c\\txt_sub_type_b";
    nor_img_click = "tips_content_container\\content_img\\btn_picclick";
    -- 头像区路径
    content_img = "tips_content_container\\content_img";
    img_fillet = "tips_content_container\\content_img\\img_fillet";
    img_avatar = "tips_content_container\\content_img\\img_avatar";
    img_btn = "tips_content_container\\content_img\\btn_picclick";

    -- 操作按钮路径
    tips_btn_container = "tips_btn_container";
    tips_btn_cancel = "tips_btn_container\\btn_cancel";
    tips_btn_ok = "tips_btn_container\\btn_ok";

    -- bubble tips tpf路径
    bubble_content_img = "content_img";
    bubble_img_avatar = "content_img\\img_avatar";
    bubble_txt_main_father = "content_txt\\txt_main_type_c";
    bubble_txt_main = "content_txt\\txt_main_type_c\\txt_main_type";
    bubble_txt_main_btn = "content_txt\\txt_main_type_c\\txt_main_type_b";
    bubble_txt_sub_father = "content_txt\\txt_sub_type_c";
    bubble_txt_sub = "content_txt\\txt_sub_type_c\\txt_sub_type";
    bubble_txt_sub_btn = "content_txt\\txt_sub_type_c\\txt_sub_type_b";
    bubble_txt_third_father = "content_txt\\txt_third_type_c";
    bubble_txt_third = "content_txt\\txt_third_type_c\\txt_third_type";
    bubble_txt_third_btn = "content_txt\\txt_third_type_c\\txt_third_type_b";
    bubble_img_click = "content_img\\btn_picclick";
    bubble_tips_all_btn = "all_btn";

    -- tpf文件名称
    tpf_normal_tips = "normal_tips.tpf";
    tpf_bubble_big_tips = "bubble_tips_big.tpf";
    tpf_bubble_small_tips = "bubble_tips_small.tpf";
    tpf_bubble_alt_tips = "bubble_tips_alt.tpf";
    tpf_normal_big_tips = "normal_tips_big.tpf";
    tpf_app_bkd_tips = "app_bkd_tips.tpf";
    tpf_web_only = "web_only_wnd.tpf"
}
client_tips_view_constant = {
    TIPS_ANIMATION_FRAME = 4;
    TIPS_INTERVAL = 2;
    TIPS_SHADOW_WIDTH = 8;
    BUBBLE_REDUCE_HEIGHT = 10;

    WIDTH_WORD_EN = 20;  -- 英文字符占10个像素
    WIDTH_WORD_CH = 15;  -- 中文字符占15个像素
}

client_tips_frame_view =
{

    init = function()
        base_utility.log("[client_tips_frame_view] init ");
    end;

    -- 以下为通用tips显示逻辑

    load_web_float_tips  = function (tips_data, web_ready_handle)
        base_utility.log("[client_tips_frame_view][show_bubble_tips]load_web_float_tips");
        ierd_tgp.tpf_ui.Require("local_web\\local_web_wnd.lua");
        local dw_bubble_dlg_id = layout_mgr.restore_layout_multi(client_tips_res.tpf_web_only);
        local web_opt = base_utility.copy_table(tips_data);
        web_opt.width = 481;
        web_opt.height = 234;
        web_opt.url = LoadStr("FLOAT_TIPS_URL");
        web_opt.delay_show_wnd = true;
        web_opt.web_ready_handle = web_ready_handle;

        url_param = {};
        url_param.tips_main_type = tips_data.tips_main_type;
        url_param.tips_type_normal = tips_data.tips_type_normal;
        url_param.tips_type_bubble = tips_data.tips_type_bubble;

        local_web_wnd.layout(dw_bubble_dlg_id, web_opt, url_param);

        return dw_bubble_dlg_id;
    end;

    -- 显示通用tips
    show_normal_tips = function (tips_data)
        local dw_normal_dlg_id = 0;
        if MainCommon.use_navtive(true) then
            base_utility.log("[client_tips_frame_view][show_bubble_tips]use native");
            if tips_data.tips_type_normal ~= nil and tips_data.tips_type_normal == 1 then
                -- 设置高度为大的tips类型
                -- client_tips_frame_view.set_normal_tips_height(dw_normal_dlg_id);
                base_utility.log("[client_tips_frame_view][show_bubble_tips]big normal");
                dw_normal_dlg_id = layout_mgr.restore_layout_multi(client_tips_res.tpf_normal_big_tips);
            else
                base_utility.log("[client_tips_frame_view][show_bubble_tips]small normal");
                dw_normal_dlg_id = layout_mgr.restore_layout_multi(client_tips_res.tpf_normal_tips);
            end;
            client_tips_frame_view.show_normal_tips_imple(dw_normal_dlg_id, tips_data);
        else
            base_utility.log("[client_tips_frame_view][show_bubble_tips]use web");
            dw_normal_dlg_id = client_tips_frame_view.load_web_float_tips(tips_data,
                    client_tips_frame_view.show_normal_tips_imple);
        end
    end;

    show_normal_tips_imple = function(dw_normal_dlg_id, tips_data)
        if dw_normal_dlg_id ~= 0 then
            -- 加入到队列中
            base_utility.log("[client_tips_frame_view][show_normal_tips]normal dlg_id = "..dw_normal_dlg_id);
            local normal_dlg_num = #(client_tips_frame_model.normal_dlg_queue);
            client_tips_frame_model.normal_dlg_queue[tips_data.id] = dw_normal_dlg_id;
            local p_normal_dlg = ui_utility.get_ctrl_ptr_by_id(dw_normal_dlg_id);
            -- 设置显示位置
            client_tips_frame_view.set_normal_tips_default_pos(dw_normal_dlg_id, p_normal_dlg);

            -- 设置具体显示内容
            client_tips_frame_view.set_normal_tips_content(dw_normal_dlg_id, p_normal_dlg, tips_data);

            if client_tips_frame_model.is_game_running == false then
                -- 没有运行中的游戏，置顶
                p_normal_dlg:BringToTop();
            else
                -- 设置不抢焦点
                ui_utility.setproperty_by_id(dw_normal_dlg_id, "NoActive", "true");
            end;

            -- 判断是否需要将气泡tips上移
            if client_tips_frame_view.need_move_bubble_for_add() == true then
                base_utility.log("[client_tips_frame_view][show_normal_tips] there are bubbles showing now, need move bubbles up");
                local move_width, move_height = ui_utility.get_control_size_by_id(dw_normal_dlg_id);
                move_height = move_height - client_tips_view_constant.BUBBLE_REDUCE_HEIGHT;
                client_tips_frame_view.move_bubble_tips_pos(true, move_height);
            elseif client_tips_frame_view.need_move_bubble_for_big(tips_data) == true then
                local move_height = 30;
                client_tips_frame_view.move_bubble_tips_pos(true, move_height);
            end;
            -- 判断是否有定时器
            if tips_data.show_duration ~= nil then
                tips_data.show_duration = tonumber(tips_data.show_duration);
                if(tips_data.show_duration > 0) then
                    client_tips_frame_view.add_show_tick(tips_data.show_duration, tips_data.id, "client_tips_frame_view.tick_close_normal_dlg");
                    p_normal_dlg:Show(TRUE);
                    local dlg_width, dlg_height = ui_utility.get_control_size_by_id(dw_normal_dlg_id);
                    client_tips_frame_view.move_tips_to_final_pos(dw_normal_dlg_id, p_normal_dlg, dlg_height, true);
                else
                    p_normal_dlg:Show(TRUE);
                    local dlg_width, dlg_height = ui_utility.get_control_size_by_id(dw_normal_dlg_id);
                    client_tips_frame_view.move_tips_to_final_pos(dw_normal_dlg_id, p_normal_dlg, dlg_height, true);
                end;
            else
                p_normal_dlg:Show(TRUE);
                local dlg_width, dlg_height = ui_utility.get_control_size_by_id(dw_normal_dlg_id);
                client_tips_frame_view.move_tips_to_final_pos(dw_normal_dlg_id, p_normal_dlg, dlg_height, true);
            end;
            --shadow_helper.create_shadow(dw_normal_dlg_id);
        else
            base_utility.log("[client_tips_frame_view] create normal tips error!");
        end
    end;

    -- 根据tips类型，决定tips高度
    set_normal_tips_height = function(dw_normal_dlg_id)
        if dw_normal_dlg_id > 0 then
            ui_utility.setproperty_by_id(dw_normal_dlg_id, "Height", 217);
        end;
    end;

    -- 通用Tips:移动到右下角,动画起始位置
    set_normal_tips_default_pos = function(dw_normal_dlg_id, p_normal_dlg)
        local tpf_ui =
        base_utility.get_component_adapter("ITpf_ui",
                "ierd_tgp.tpf_ui.GetTPFUI();");
        local sys_param = ierd_tgp.tpf_ui.SysParams:new();
        tpf_ui:get_sys_params(sys_param);
        local work_area_width = sys_param.work_area_width;
        local work_area_height = sys_param.work_area_height;
        local dlg_width, dlg_height = ui_utility.get_control_size_by_id(dw_normal_dlg_id);
        sys_param:delete();
        -- 移动到右下角
        local rect_dlg = p_normal_dlg:GetRectEx(TRUE,TRUE);
        rect_dlg.left = work_area_width - dlg_width + client_tips_view_constant.TIPS_INTERVAL;
        -- rect_dlg.top = work_area_height - dlg_height - 1;
        rect_dlg.top = work_area_height + client_tips_view_constant.TIPS_INTERVAL;
        rect_dlg.right = rect_dlg.left + dlg_width;
        rect_dlg.bottom = rect_dlg.top + dlg_height;
        base_utility.log("[client_tips_frame_view][set_normal_tips_content]move to right corner,dlg_id=" .. dw_normal_dlg_id .. " position(left, top, right, bottom) = (" .. rect_dlg.left .. "," .. rect_dlg.top .. "," .. rect_dlg.right .. "," .. rect_dlg.bottom);
        p_normal_dlg:MoveEx(rect_dlg,TRUE);
    end;

    -- 设置通用tips显示内容
    set_normal_tips_content = function (dw_normal_dlg_id, p_normal_dlg, tips_data)
        -- body
        if dw_normal_dlg_id == 0 or p_normal_dlg == nil then
            base_utility.log("[client_tips_frame_view]set normal tips content, dlg not exist");
            return;
        end;
        -- 设置标题部分
        if tips_data.tips_setting == nil then
            -- 设置按钮不可见
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.title_set, "Visible", "false");
        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.title_set, "Visible", "true");
        end;

        local title_name = LoadStr("CLIENT_TIPS_FRAME_REMINDING");
        if tips_data.tips_title ~= nil then
            title_name = tips_data.tips_title;
        end;
        ui_utility.setproperty_by_path(dw_normal_dlg_id,
                client_tips_res.title_txt, "Caption",
                title_name);
        local has_icon = false;

        -- 设置头像部分
        -- 如果tips_icon填写game_id则转为game_id对应url
        if type(tips_data.tips_icon) == "number" then
            local game_lib = base_utility.get_component_adapter("IGame_library",
                    "ierd_tgp.game_library.Get_game_library_adapter();");
            local game_info = ierd_tgp.game_library.GameDetailInfo:new();
            if game_lib ~= nil and game_info ~= nil then
                game_lib:get_game_detail_info(tips_data.tips_icon, game_info);
                tips_data.tips_icon = game_info.icon_url;
            end
            if game_info ~= nil then
                game_info:delete();
            end
            -- 如果转换失败则置空
            if type(tips_data.tips_icon) ~= "string" or tips_data.tips_icon == "" then
                tips_data.tips_icon = nil;
            end
        end
        if tips_data.tips_icon ~= nil then
            has_icon = true;
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.content_img, "Visible", "true");
            -- 这里加个判断，如果不是http开头的图片，则不加默认图片前缀
            local add_head = true;
            if string.find(tips_data.tips_icon, "^http") ~= nil then
                add_head = true;
            else
                add_head = false;
            end;
            local img_url = "";
            if tips_data.icon_type ~= nil and tips_data.icon_type == 0 then
                -- 显示圆形浮层
                -- 拼接头像地址
                if add_head == true then
                    img_url = "ONEIMAGE:client_tips\\def_circular_img.png|"..tips_data.tips_icon..";Stretch;null;";
                else
                    img_url = "ONEIMAGE:"..tips_data.tips_icon..";Stretch;null;";
                end;
                ui_utility.setproperty_by_path(dw_normal_dlg_id,
                        client_tips_res.img_fillet, "Visible", "true");
            else
                if add_head == true then
                    img_url = "ONEIMAGE:client_tips\\def_square_img.png|"..tips_data.tips_icon..";Stretch;null;";
                else
                    img_url = "ONEIMAGE:"..tips_data.tips_icon..";Stretch;null;";
                end;

                ui_utility.setproperty_by_path(dw_normal_dlg_id,
                        client_tips_res.img_fillet, "Visible", "false");
            end;
            -- 显示头像
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.img_avatar, "Background",
                    img_url);
        else
            -- 不显示头像区域
            has_icon = false;
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.content_img, "Visible", "false");
        end;
        -- 设置窗口宽度
        if tips_data.tips_type_normal == nil or tips_data.tips_type_normal == 0 then
            client_tips_frame_view.set_normal_tip_content_width(dw_normal_dlg_id, tips_data, 240, 180);
        else
            -- 设置大窗口内容区域宽度
            client_tips_frame_view.set_normal_tip_content_width(dw_normal_dlg_id, tips_data, 248, 162);
        end;



        -- 设置内容区域
        local main_title = nil;
        if tips_data.main_title ~= nil then
            main_title = tips_data.main_title;
        end;

        local has_subtitle = false;
        if tips_data.sub_title ~= nil then
            has_subtitle = true;
        end;
        -- 因为有副标题和没有副标题时，主标题字体大小不一样，所以用了2个控件，通过隐藏显示来达到字体大小改变的效果
        if main_title ~= nil then
            if tips_data.tips_type_normal == nil or tips_data.tips_type_normal == 0 then
                -- 只有正常大小tips需要做此判断，大tips不需要做此判断
                if has_subtitle == true then
                    client_tips_frame_view.set_rich_box_txt(dw_normal_dlg_id,
                            client_tips_res.txt_main_type,
                            main_title);
                else
                    client_tips_frame_view.set_rich_box_txt(dw_normal_dlg_id,
                            client_tips_res.txt_main_type_big,
                            main_title);
                end;
            else
                client_tips_frame_view.set_rich_box_txt(dw_normal_dlg_id,
                        client_tips_res.txt_main_type,
                        main_title);
            end;
        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.txt_main_type, "Visible", "false");
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.txt_main_type_big, "Visible", "false");
        end;

        -- 设置主标题位置
        if tips_data.tips_type_normal == nil or tips_data.tips_type_normal == 0 then
            client_tips_frame_view.set_normal_maintitle_pos(dw_normal_dlg_id, has_subtitle, has_icon);
        else
            client_tips_frame_view.set_normal_big_maintitle_pos(dw_normal_dlg_id,
                    has_subtitle, has_icon);
        end;


        if tips_data.sub_title ~= nil then
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.txt_sub_type, "Visible", "true");
            client_tips_frame_view.set_rich_box_txt(dw_normal_dlg_id,
                    client_tips_res.txt_sub_type,
                    tips_data.sub_title);
            -- 设置副标题位置
            local has_maintitle = false;
            if tips_data.main_title ~= nil then
                has_maintitle = true;
            else
                has_maintitle = false;
            end;
            if tips_data.tips_type_normal == nil or tips_data.tips_type_normal == 0 then
                client_tips_frame_view.set_normal_subtitle_pos(dw_normal_dlg_id, has_maintitle, has_icon);
            else
                -- 设置大tips副标题位置
                client_tips_frame_view.set_normal_big_subtitle_pos(dw_normal_dlg_id,
                        has_maintitle, has_icon);
            end;

        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.txt_sub_type, "Visible", "false");
        end;

        -- 设置头像点击按钮是否可见
        client_tips_frame_view.set_normal_pic_btn(dw_normal_dlg_id, tips_data);

        -- 设置响应按钮是否可见
        -- client_tips_frame_view.set_normal_resp_btn(dw_normal_dlg_id, tips_data);

        -- 设置操作区域
        if tips_data.tips_ok_btn ~= nil  and tips_data.tips_ok_btn ~= "" then
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_ok, "Visible", "true");
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_ok, "Caption",
                    tips_data.tips_ok_btn);
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_ok, "XOffset", "97");
        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_ok, "Visible", "false");
        end;
        if tips_data.tips_cancel_btn ~= nil and tips_data.tips_cancel_btn ~= "" then
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_cancel, "Visible", "true");
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_cancel, "Caption",
                    tips_data.tips_cancel_btn);
        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_cancel, "Visible", "false");
            -- 没有取消按钮，这移动确定按钮
            ui_utility.setproperty_by_path(dw_normal_dlg_id,
                    client_tips_res.tips_btn_ok, "XOffset", "207");
        end;

    end;

    -- 通用tips显示定时器回调函数
    tick_close_normal_dlg = function (tips_id)
        -- 得到对应的dlg_id
        local dlg_id = client_tips_frame_model.normal_dlg_queue[tips_id];
        if dlg_id ~= nil then
            base_utility.log("[client_tips_frame_view][tick_close_normal_dlg] tip_id=" .. tips_id .. ",dlg_id = " .. dlg_id);
        end;
        client_tips_frame_view.close_normal_tips_dlg(tips_id,
                client_tips_control_constant.close_type_timeout);
        -- 如果有定时器，关闭定时器
        local tpfui = base_utility.get_component_adapter("ITpf_ui",
                "ierd_tgp.tpf_ui.GetTPFUI();");
        if tpfui ~= nil then
            tpfui:RemoveInterval("client_tips_frame_view.tick_close_normal_dlg", tips_id);
        end;
    end;

    -- 通用tips：关闭
    close_normal_tips_dlg = function (close_tip_id, close_type)

        local wait_remove_tips_num = #(client_tips_frame_model.wait_del_tips_queue);
        local to_remove_tips = {};
        to_remove_tips.tip_id = close_tip_id;
        to_remove_tips.tip_type = client_tips_model_constant.TIPS_MAIN_TYPE_NORMAL;
        to_remove_tips.close_type = close_type;
        client_tips_frame_model.wait_del_tips_queue[wait_remove_tips_num + 1] = to_remove_tips;
        if wait_remove_tips_num == 0 then
            client_tips_frame_view.start_close_timer();
        end;
    end;

    -- 以下为气泡tips显示逻辑

    -- 显示气泡tips
    show_bubble_tips = function (tips_data)
        local dw_bubble_dlg_id = 0;

        if MainCommon.use_navtive(true) then
            base_utility.log("[client_tips_frame_view][show_bubble_tips]use native");
            if tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 1 then
                -- 显示长图
                dw_bubble_dlg_id = layout_mgr.restore_layout_multi(client_tips_res.tpf_bubble_big_tips);
            elseif tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 2 then
                -- 带按钮的小窗
                dw_bubble_dlg_id = layout_mgr.restore_layout_multi(client_tips_res.tpf_bubble_alt_tips);
            else
                -- 显示方图
                dw_bubble_dlg_id = layout_mgr.restore_layout_multi(client_tips_res.tpf_bubble_small_tips);
            end;
            client_tips_frame_view.show_bubble_tips_impl(dw_bubble_dlg_id, tips_data);
        else
            base_utility.log("[client_tips_frame_view][show_bubble_tips]use web");
            dw_bubble_dlg_id = client_tips_frame_view.load_web_float_tips(tips_data,
                    client_tips_frame_view.show_bubble_tips_impl);
        end;
    end;

    show_bubble_tips_impl = function(dw_bubble_dlg_id, tips_data)
        if dw_bubble_dlg_id ~= 0 then
            -- 加入到队列中
            base_utility.log("[client_tips_frame_view][show_bubble_tips]show bubble tip, tip_id = " .. tips_data.id .. ", dlg_id=" .. dw_bubble_dlg_id);
            client_tips_frame_model.bubble_dlg_queue[tips_data.id] = dw_bubble_dlg_id;
            local p_bubble_dlg = ui_utility.get_ctrl_ptr_by_id(dw_bubble_dlg_id);
            client_tips_frame_view.set_bubble_tips_default_pos(dw_bubble_dlg_id, p_bubble_dlg);
            -- 设置弹框内容
            if tips_data.native == true then
                client_tips_frame_view.set_bubble_tips_content(dw_bubble_dlg_id, p_bubble_dlg, tips_data);
            end

            if client_tips_frame_model.is_game_running == false then
                -- 没有运行中的游戏，置顶
                if tips_data.native == true then
                    p_bubble_dlg:BringToTop();
                end
            else
                -- 设置不抢焦点
                ui_utility.setproperty_by_id(dw_bubble_dlg_id, "NoActive", "true");
            end;

            -- 判断是否有定时器
            if tips_data.show_duration ~= nil then
                tips_data.show_duration = tonumber(tips_data.show_duration);
                if(tips_data.show_duration > 0) then
                    client_tips_frame_view.add_show_tick(tips_data.show_duration, tips_data.id, "client_tips_frame_view.tick_close_bubble_dlg");
                end;
            end;
            if tips_data.delay_show_wnd ~= true then
                p_bubble_dlg:Show(TRUE);
            end
            local dlg_width, dlg_height = ui_utility.get_control_size_by_id(dw_bubble_dlg_id);
            client_tips_frame_view.move_tips_to_final_pos(dw_bubble_dlg_id, p_bubble_dlg, dlg_height, true);
        else
            base_utility.log("[client_tips_frame_view] create bubble tips error!");
        end
    end;

        -- 设置通用tips显示内容
    set_bubble_tips_content = function (dw_bubble_dlg_id, p_bubble_dlg, tips_data)
        -- body
        if dw_bubble_dlg_id == 0 or p_bubble_dlg == nil then
            base_utility.log("[client_tips_frame_view]set bubble tips content, dlg not exist");
        end;

        local use_poster_img = false;
        if tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 2 then
            use_poster_img = true;
        end
        -- 设置头像部分
        -- 如果tips_icon填写game_id则转为game_id对应url
        if type(tips_data.tips_icon) == "number" then
            
            local poster_url = "";
            if use_poster_img and nil ~= banner_model then
                local base_info = banner_model.get_game_base_info(tips_data.tips_icon);
                if nil ~= base_info then
                    poster_url = base_info.poster_url;
                end
            end;

            if poster_url ~= nil and poster_url ~= "" then
                tips_data.tips_icon = poster_url;
            else
                local game_lib = base_utility.get_component_adapter("IGame_library",
                "ierd_tgp.game_library.Get_game_library_adapter();");
                local game_info = ierd_tgp.game_library.GameDetailInfo:new();
                if game_lib ~= nil and game_info ~= nil then                     
                    game_lib:get_game_detail_info(tips_data.tips_icon, game_info);
                    tips_data.tips_icon = game_info.icon_url;
                end
                if game_info ~= nil then
                    game_info:delete();
                end
            end

            -- 如果转换失败则置空
            if type(tips_data.tips_icon) ~= "string" or tips_data.tips_icon == "" then
                 tips_data.tips_icon = nil;
            end
        end

        if tips_data.tips_icon ~= nil then
            -- 这里加个判断，如果不是http开头的图片，则不加默认图片前缀
            local add_head = true;
            if string.find(tips_data.tips_icon, "^http") ~= nil then
                add_head = true;
            else
                add_head = false;
            end;
            local img_url = "ONEIMAGE:client_tips\\def_circular_img.png|"..tips_data.tips_icon;
            if tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 1 then
                if add_head == true then
                    img_url = "ONEIMAGE:client_tips\\def_rectangle_img.png|"..tips_data.tips_icon..";Stretch;null;";
                else
                    img_url = "ONEIMAGE:"..tips_data.tips_icon..";Stretch;null;";
                end;
            else
                if add_head == true then
                    img_url = "ONEIMAGE:client_tips\\def_square_img.png|"..tips_data.tips_icon..";Stretch;null;";
                else
                    img_url = "ONEIMAGE:"..tips_data.tips_icon..";Stretch;null;";
                end;
                
            end;
            ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                    client_tips_res.bubble_content_img, "Visible", "true");
            -- 显示头像
            ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                    client_tips_res.bubble_img_avatar, "Background",
                    img_url);
        else
            -- 不显示头像区域
            ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                    client_tips_res.bubble_content_img, "Visible", "false");
        end;

        -- 设置内容区域
        local main_title = LoadStr("CLIENT_TIPS_FRAME_PROMPT");
        if tips_data.main_title ~= nil then
            main_title = tips_data.main_title;
        end;
        client_tips_frame_view.set_rich_box_txt(dw_bubble_dlg_id,
                            client_tips_res.bubble_txt_main, main_title);

        if tips_data.sub_title ~= nil then
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, 
                                client_tips_res.bubble_txt_sub, "Visible", "true");
            client_tips_frame_view.set_rich_box_txt(dw_bubble_dlg_id,
                                client_tips_res.bubble_txt_sub, tips_data.sub_title);
        else
            ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                client_tips_res.bubble_txt_sub, "Visible", "false");
        end;

        if tips_data.third_title ~= nil then
            if tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 2 then
                ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                    client_tips_res.bubble_txt_third, "Visible", "false");
                ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                                client_tips_res.bubble_txt_third_btn, "Caption", 
                                            tips_data.third_title);
                
            else
                ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                    client_tips_res.bubble_txt_third, "Visible", "true");
                client_tips_frame_view.set_rich_box_txt(dw_bubble_dlg_id,
                                client_tips_res.bubble_txt_third, tips_data.third_title);
            end
        else
            ui_utility.setproperty_by_path(dw_bubble_dlg_id,
                client_tips_res.bubble_txt_third, "Visible", "false");
        end;

        -- 设置文本显示位置
        client_tips_frame_view.set_bubble_maintitle_pos(dw_bubble_dlg_id, tips_data);

        -- 设置响应按钮是否可见
        client_tips_frame_view.set_bubble_resp_btn(dw_bubble_dlg_id, tips_data);
    end;

    -- 气泡Tips:移动到右下角,动画起始位置
    set_bubble_tips_default_pos = function(dw_bubble_dlg_id, p_bubble_dlg)
        -- 判断是否有气泡tips存在，如果有，则根据气泡tips位置决定现在显示的tips位置
        local temp_bubble_tips_num = #(client_tips_frame_model.bubble_tips_queue);
        -- 大于1，以及遍历结束为(temp_bubble_tips_num - 1),都是为了排除自身
        if temp_bubble_tips_num > 1 then
            -- 遍历查找最上面的一个dlg，遍历的原因：防止因为未知异常导致气泡窗口未创建，可是数据已经存在
            local top_bubble_dlg_id = 0;
            for tips_i = 1, (temp_bubble_tips_num - 1) do
                local tips_id = client_tips_frame_model.bubble_tips_queue[tips_i].id;
                for tips_dlg_key, tips_dlg_value in pairs(client_tips_frame_model.bubble_dlg_queue) do
                    if tips_id == tips_dlg_key then
                        top_bubble_dlg_id = tips_dlg_value;
                        break;
                    end;
                end;
            end;
            if top_bubble_dlg_id > 0 then
                base_utility.log("[client_tips_frame_view][set_bubble_tips_default_pos]set position relative to top bubble, top bubble dlg_id = " .. top_bubble_dlg_id);
                client_tips_frame_view.set_bubble_dlg_position(dw_bubble_dlg_id, top_bubble_dlg_id);
                return;
            end;
        else
            base_utility.log("[client_tips_frame_view][set_bubble_tips_default_pos] this is the first bubble dlg");
        end;

        -- 判断当前是否有通用tips在显示
        local normal_dlg_num = 0;
        for temp_key,temp_vale in pairs(client_tips_frame_model.normal_dlg_queue) do
            if temp_key ~= nil then
                normal_dlg_num = normal_dlg_num + 1;
            end;
        end;

        local has_normal_in_corner, in_corner_dlg_id, corner_dlg_type = client_tips_frame_view.has_normal_dlg_in_corner();
        base_utility.log("[client_tips_frame_view] in_corner_dlg_id =" .. in_corner_dlg_id);

        if normal_dlg_num > 0 and has_normal_in_corner == true then
            -- 获得normal_dlg的dlg id

            base_utility.log("[client_tips_frame_view][set_bubble_tips_default_pos] has normal tips, set bubble tip position relative to normal tip");
            client_tips_frame_view.set_bubble_dlg_position(dw_bubble_dlg_id, in_corner_dlg_id);
            return;
        end;
        -- 相对于桌面位置
        base_utility.log("[client_tips_frame_view][set_bubble_tips_default_pos] set bubble tip position relative to windows");
        client_tips_frame_view.set_bubble_dlg_position(dw_bubble_dlg_id, 0);
    end;

    -- 设置bubble弹框的默认显示位置
    set_bubble_dlg_position = function (cur_dlg_id, refer_dlg_id)
        local p_cur_dlg = ui_utility.get_ctrl_ptr_by_id(cur_dlg_id);
        local dlg_width, dlg_height = ui_utility.get_control_size_by_id(cur_dlg_id);
        if p_cur_dlg == nil then
            base_utility.log("[client_tips_frame_view][set_bubble_dlg_position]cur dlg is nil ,faile to remove");
            return;
        end;
        local cur_rect = p_cur_dlg:GetRectEx(TRUE,TRUE);

        if refer_dlg_id > 0 then
            -- 相对于refer_dlg_id位置
            local p_refer_dlg = ui_utility.get_ctrl_ptr_by_id(refer_dlg_id);
            if p_refer_dlg == nil then
                base_utility.log("[client_tips_frame_view][set_bubble_dlg_position] refer dlg is nil, failed to remove");
                return;
            end;
            local refer_rect = p_refer_dlg:GetRectEx(TRUE,TRUE);
            cur_rect.left = refer_rect.left;
            cur_rect.top = refer_rect.top + client_tips_view_constant.TIPS_INTERVAL + client_tips_view_constant.TIPS_SHADOW_WIDTH;
            cur_rect.right = cur_rect.left + dlg_width;
            cur_rect.bottom = cur_rect.top + dlg_height;
        else
            -- 相对与桌面位置
            local tpf_ui =
            base_utility.get_component_adapter("ITpf_ui",
                "ierd_tgp.tpf_ui.GetTPFUI();");
            local sys_param = ierd_tgp.tpf_ui.SysParams:new();
            tpf_ui:get_sys_params(sys_param);
            local work_area_width = sys_param.work_area_width;
            local work_area_height = sys_param.work_area_height;
            sys_param:delete();

            cur_rect.left = work_area_width - dlg_width + client_tips_view_constant.TIPS_INTERVAL;
            cur_rect.top = work_area_height + client_tips_view_constant.TIPS_INTERVAL;
            cur_rect.right = cur_rect.left + dlg_width;
            cur_rect.bottom = cur_rect.top + dlg_height;
        end;
        base_utility.log("[client_tips_frame_view][set_bubble_dlg_position] position(left, top, right, bottom) = (" .. cur_rect.left .. "," .. cur_rect.top .. "," .. cur_rect.right .. "," .. cur_rect.bottom);
        p_cur_dlg:MoveEx(cur_rect,TRUE);
    end;

    -- 气泡tips显示定时器回调函数
    tick_close_bubble_dlg = function (tips_id)
        -- 得到对应的dlg_id
        local dlg_id = client_tips_frame_model.bubble_dlg_queue[tips_id];
        if dlg_id ~= nil then
            base_utility.log("[client_tips_frame_view][tick_close_bubble_dlg] tip_id=" .. tips_id .. ",dlg_id = " .. dlg_id);
        end;
        
        client_tips_frame_view.close_bubble_tips_dlg(tips_id,
                client_tips_control_constant.close_type_timeout);
        
        -- 如果有定时器，关闭定时器
        local tpfui = base_utility.get_component_adapter("ITpf_ui",
            "ierd_tgp.tpf_ui.GetTPFUI();");
        if tpfui ~= nil then
            tpfui:RemoveInterval("client_tips_frame_view.tick_close_bubble_dlg", tips_id);
        end;
    end;

    -- 气泡tips：关闭
    close_bubble_tips_dlg = function (close_tip_id, close_type)
        local wait_remove_tips_num = #(client_tips_frame_model.wait_del_tips_queue);
        local to_remove_tips = {};
        to_remove_tips.tip_id = close_tip_id;
        to_remove_tips.tip_type = client_tips_model_constant.TIPS_MAIN_TYPE_BUBBLE;
        to_remove_tips.close_type = close_type;
        client_tips_frame_model.wait_del_tips_queue[wait_remove_tips_num + 1] = to_remove_tips;
        if wait_remove_tips_num == 0 then
            -- 启动关闭tips计时器
            base_utility.log("[client_tips_frame_view]wait remove tips num = 0, start close timer");
            client_tips_frame_view.start_close_timer();
        else
            base_utility.log("[client_tips_frame_view]wait remove tips num ="..wait_remove_tips_num..", not start timer");
        end;
    end;

    -- 以下为web tips显示逻辑

    -- 显示web tips
    show_web_tips = function (tips_data)
        -- body
    end;

    -- 以下为tips移动逻辑

    -- 判断添加通用tips时，是否需要移动气泡tips
    need_move_bubble_for_add = function ()
        return client_tips_frame_view.is_bubble_in_corner();
    end;

    -- 显示大的通用tips时，判断是否要移动气泡tips
    need_move_bubble_for_big = function (tips_data)
        local bubble_tips_num = #(client_tips_frame_model.bubble_tips_queue);

        if bubble_tips_num == 0 or tips_data.tips_type_normal == nil or tips_data.tips_type_normal == 0 then
            return false;
        end;
        -- 判断是否存在其他big normal tips
        local has_other_big_tips = false;
        local normal_tips_num = #(client_tips_frame_model.normal_tips_queue);
        for normal_index = 1, normal_tips_num do
            local normal_tip_id = client_tips_frame_model.normal_tips_queue[normal_index].id;
            local tips_type_normal = client_tips_frame_model.normal_tips_queue[normal_index].tips_type_normal;
            if normal_tip_id ~= tips_data.id then
                if tips_type_normal ~= nil and tips_type_normal == 1 then
                    -- 判断是否在拐角
                    local tip_dlg_id = client_tips_frame_model.get_normal_tip_dlg_id(normal_tip_id);
                    local is_in_corner = client_tips_frame_view.is_dlg_in_corner(tip_dlg_id);
                    if is_in_corner == true then
                        has_other_big_tips = true;
                        break;
                    end;
                end;
            end;
        end;
        if has_other_big_tips == true then
            return false;
        else
            return true;
        end;
    end;

    -- 判断关闭通用tips时，是否需要移动气泡tips
    need_move_bubble_for_close_norm = function (close_tip_normal_type, is_close_dlg_in_corner)
        local need_move = false;
        local move_height = 0;

        if is_close_dlg_in_corner == false then
            return false, 0;
        end;
        if client_tips_frame_view.is_bubble_in_corner() == true then
            need_move = false;
            return need_move, 0;
        end;
        -- 如果当前的气泡tips不在角落位置，判断是否需要下移气泡tips
        local normal_tips_num = #(client_tips_frame_model.normal_tips_queue);
        if normal_tips_num == 0 then
            need_move = not (client_tips_frame_view.is_bubble_in_corner());
            return need_move, 0;
        end;

        local has_in_corner_normal_dlg, in_corner_dlg_id, corner_dlg_type = client_tips_frame_view.has_normal_dlg_in_corner();

        if close_tip_normal_type == 1 then
            -- 大tips
            if has_in_corner_normal_dlg == true and corner_dlg_type == 1 then
                need_move = false;
            elseif has_in_corner_normal_dlg == true and corner_dlg_type == 0 then
                need_move = true;
                move_height = 39;
            else
                need_move = true;
            end;
        else
            -- 小tips
            if has_in_corner_normal_dlg == true then
                need_move =  false;
            else
                need_move = true;
            end;
        end;
        return need_move, move_height;
    end;

    -- 判断关闭气泡tips时，是否需要移动气泡tips
    need_move_bubble_for_close_bubb = function (close_tip_id)
        local need_move = false;
        -- if client_tips_frame_view.is_bubble_in_corner() == true then
        --     need_move = false;
        --     return need_move;
        -- end;


        local bubble_tips_num = #(client_tips_frame_model.bubble_tips_queue);

        if bubble_tips_num == 0 then
            need_move = false;
            return need_move;
        end;
        if close_tip_id == client_tips_frame_model.bubble_tips_queue[bubble_tips_num].id then
            -- 关闭的是最新的tips,不需要移动
            need_move = false;
            return need_move;
        end;

        need_move = true;
        return need_move;

    end;

    -- 判断移动通用tips时，是否需要移动气泡tips
    need_move_bubble_for_move = function(move_tip_normal_type)
        local need_move = false;
        local move_height = 0;
        local bubble_tips_num = #(client_tips_frame_model.bubble_tips_queue);
        if bubble_tips_num == 0 then
            need_move = false;
            return need_move;
        end;
        need_move = not(client_tips_frame_view.is_bubble_in_corner());
        if need_move == false then
            return need_move;
        end;
        -- 判断是否有在右下角的通用tips
        local has_in_corner_normal_dlg, in_corner_dlg_id, corner_dlg_type = client_tips_frame_view.has_normal_dlg_in_corner();

        if move_tip_normal_type == 1 then
            -- 大tips
            if has_in_corner_normal_dlg == true and corner_dlg_type == 1 then
                need_move = false;
            elseif has_in_corner_normal_dlg == true and corner_dlg_type == 0 then
                -- 右下角存在小的通用tips，且不存在大的通用tips，需要判断是否需要移动tips
                local is_need_move = client_tips_frame_view.is_bubble_need_move(in_corner_dlg_id);
                if is_need_move == true then
                    need_move = true;
                    move_height = 39;
                else
                    need_move = false;
                end;
            else
                need_move = true;
            end;
        else
            -- 小tips
            if has_in_corner_normal_dlg == true then
                need_move =  false;
            else
                need_move = true;
            end;
        end;
        return need_move, move_height;
    end; 

    -- 判断当前的气泡tips是否在右下角
    is_bubble_in_corner = function ()
        local is_in_corner = true;
        local oldest_dlg_id = client_tips_frame_view.get_oldest_bubble_dlg();
        if oldest_dlg_id > 0 then
            is_in_corner = client_tips_frame_view.is_dlg_in_corner(oldest_dlg_id);
        end;
        return is_in_corner;
    end;

    -- 判断在小 normal tips上面的bubble tips是否需要移动
    is_bubble_need_move = function(normal_dlg_id)
        local is_in_corner = true;
        local oldest_dlg_id = client_tips_frame_view.get_oldest_bubble_dlg();
        if oldest_dlg_id > 0 then
            is_in_corner = client_tips_frame_view.is_bubble_dlg_need_down(oldest_dlg_id, normal_dlg_id);
        end;
        return is_in_corner;
    end;

    -- 获取最下面的bubble tip
    get_oldest_bubble_dlg = function ()
        local oldest_dlg_id = 0;
        for tip_index = 1, #(client_tips_frame_model.bubble_tips_queue) do
            local tip_id = client_tips_frame_model.bubble_tips_queue[tip_index].id;
            for temp_k, temp_v in pairs(client_tips_frame_model.bubble_dlg_queue) do
                if tip_id == temp_k then
                    oldest_dlg_id = temp_v;
                    break;
                end;
            end;
            break;
        end;
        return oldest_dlg_id;
    end;

    -- 判断当前的bubble dlg是否需要往下移动；在拖动大tips时，需要做的判断，其他情况不需要做此判断
    is_bubble_dlg_need_down = function (bubble_dlg_id, in_corner_dlg_id)
        local is_need_down = true;
        local p_dlg = ui_utility.get_ctrl_ptr_by_id(bubble_dlg_id);
        if p_dlg ~= nil and bubble_dlg_id > 0 and in_corner_dlg_id > 0 then
            -- 找到最老的气泡tips
            local rect = p_dlg:GetRectEx(TRUE,TRUE);
            local width, height = ui_utility.get_control_size_by_id(bubble_dlg_id);
            local normal_width, normal_height = ui_utility.get_control_size_by_id(in_corner_dlg_id);

            local tpf_ui =
            base_utility.get_component_adapter("ITpf_ui",
                "ierd_tgp.tpf_ui.GetTPFUI();");
            local sys_param = ierd_tgp.tpf_ui.SysParams:new();
            tpf_ui:get_sys_params(sys_param);
            local work_area_width = sys_param.work_area_width;
            local work_area_height = sys_param.work_area_height;
            sys_param:delete();

            base_utility.log("ret.top=" .. rect.top .. ";work_area_height=" .. work_area_height .. ";height=" .. height .. ";normal_height=" .. normal_height);
            -- 判断是否需要移动的条件：气泡tips遮住了通用tips应该显示的位置
            is_need_down = (rect.top < work_area_height - height - normal_height);
        else
            base_utility.log("[client_tips_frame_view][is_dlg_in_corner]get dlg id failed dlg_id =".. dlg_id .." or p_oldest_dlg = nil");
        end;
        return is_need_down;
    end;
    -- 判断当前dlg是否在右下角位置
    is_dlg_in_corner = function (dlg_id)
        local is_in_corner = true;
        local p_dlg = ui_utility.get_ctrl_ptr_by_id(dlg_id);
        if dlg_id > 0  and p_dlg ~= nil then
            -- 找到最老的气泡tips
            local rect = p_dlg:GetRectEx(TRUE,TRUE);
            local width, height = ui_utility.get_control_size_by_id(dlg_id);

            local tpf_ui =
            base_utility.get_component_adapter("ITpf_ui",
                "ierd_tgp.tpf_ui.GetTPFUI();");
            local sys_param = ierd_tgp.tpf_ui.SysParams:new();
            tpf_ui:get_sys_params(sys_param);
            local work_area_width = sys_param.work_area_width;
            local work_area_height = sys_param.work_area_height;
            sys_param:delete();

            -- 判断是否需要移动的条件：气泡tips遮住了通用tips应该显示的位置
            is_in_corner = (rect.top >= work_area_height - 1.5 * height)
                        and (rect.left >= work_area_width - 1.5 * width);
        else
            base_utility.log("[client_tips_frame_view][is_dlg_in_corner]get dlg id failed dlg_id =".. dlg_id .." or p_oldest_dlg = nil");
        end;
        return is_in_corner;
    end;

    -- 判断角落上是否有通用tips
    has_normal_dlg_in_corner = function ()

        local has_in_corner_normal_dlg = false;
        local in_corner_dlg_id = 0;
        local in_corner_dlg_type = 0;
        local normal_tips_num = #(client_tips_frame_model.normal_tips_queue);

        -- 判断是否存在big normal tip or normal tip
        local in_corner_dlg_list = {};

        for normal_index = 1, normal_tips_num do
            local normal_tip_id = client_tips_frame_model.normal_tips_queue[normal_index].id;
            local normal_tip_type = client_tips_frame_model.normal_tips_queue[normal_index].tips_type_normal;
            local tip_dlg_id = client_tips_frame_model.get_normal_tip_dlg_id(normal_tip_id);
            -- 判断该tips的位置
            local is_in_corner = client_tips_frame_view.is_dlg_in_corner(tip_dlg_id);
            if is_in_corner == true then
                if normal_tip_type == nil then
                    in_corner_dlg_list[tip_dlg_id] = 0;
                else
                    in_corner_dlg_list[tip_dlg_id] = normal_tip_type;
                end;
            end;
        end;
        -- 判断是否存在在拐角的tips，以及tips类型
        local corner_list_length = 0;
        for i , v in pairs(in_corner_dlg_list) do
            corner_list_length = corner_list_length + 1;
        end;
        
        if corner_list_length == 0 then
            return false, 0, 0;
        end;
        local has_big_type = false;
        for key , value in pairs(in_corner_dlg_list) do
            if value == 1 then
                has_in_corner_normal_dlg = true;
                in_corner_dlg_id = key;
                in_corner_dlg_type = 1;
                has_big_type = true;
                break;
            end;
        end;
        if has_big_type == false then
            for key , value in pairs(in_corner_dlg_list) do
                has_in_corner_normal_dlg = true;
                in_corner_dlg_id = key;
                in_corner_dlg_type = 0;
                break;
            end;
        end;
        return has_in_corner_normal_dlg, in_corner_dlg_id, in_corner_dlg_type;
    end;


    -- 异步定时器
    start_close_timer = function()
        local tpfui = ierd_tgp.tpf_ui.GetTPFUI();
        if nil ~= tpfui then
            tpfui:AddInterval("client_tips_frame_view.on_close_timer", client_tips_control_constant.CLOSE_TIPS_INTERVAL, 0);
        end;
    end;

    -- 停止定时器
    stop_close_timer = function()
        local tpfui = ierd_tgp.tpf_ui.GetTPFUI();
        if nil ~= tpfui then
            tpfui:RemoveInterval("client_tips_frame_view.on_close_timer", 0);
        end;
    end;

    -- 异步事件处理
    on_close_timer = function()
        local wait_close_tips_num = #(client_tips_frame_model.wait_del_tips_queue);
        if wait_close_tips_num > 0 then
            if client_tips_frame_control.is_show_animation == true then
                base_utility.log("[client_tips_frame_view][on_close_timer] now is show animation, wait a while");
                return;
            end;
            if client_tips_frame_control.is_showing_tip == true then
                base_utility.log("[client_tips_frame_view][on_close_timer] now is showing tips, wait a while");
                return;
            else
                local tips_wait_temp = client_tips_frame_model.wait_del_tips_queue[1];
                table.remove(client_tips_frame_model.wait_del_tips_queue, 1);

                local tip_type = tips_wait_temp.tip_type;
                
                if tip_type == client_tips_model_constant.TIPS_MAIN_TYPE_NORMAL then
                    -- 关闭通用tips
                    base_utility.log("[client_tips_frame_view]close normal tips, tip_id = " .. tips_wait_temp.tip_id);
                    client_tips_frame_view.remove_normal_tip_in_tick(tips_wait_temp);
                elseif tip_type == client_tips_model_constant.TIPS_MAIN_TYPE_BUBBLE then
                    -- 关闭气泡tips
                    client_tips_frame_control.is_closing_tip = true;
                    base_utility.log("[client_tips_frame_view]close bubble tips, tip_id = " .. tips_wait_temp.tip_id);
                    client_tips_frame_view.remove_bubble_tip_in_tick(tips_wait_temp);
                elseif tip_type == client_tips_model_constant.TIPS_MAIN_TYPE_WEB then
                    -- 关闭web tips
                    base_utility.log("[client_tips_frame_view]begin close web tips");
                    client_tips_frame_view.remove_web_tip_in_tick(tips_wait_temp);
                end;

            end;
        else
            client_tips_frame_view.stop_close_timer();
        end;
    end;

    -- 在定时器里面移除通用tips窗口
    remove_normal_tip_in_tick = function (tip_wait)
        local tip_id = tip_wait.tip_id;
        local dlg_id = client_tips_frame_model.get_normal_tip_dlg_id(tip_id);
        local move_width = 0;
        local move_height = 0;
        local need_move_bubble = false;
        local temp_move_height = 0;
        -- 关闭窗口
        if dlg_id ~= nil and dlg_id > 0 then
            move_width, temp_move_height = ui_utility.get_control_size_by_id(dlg_id);
        else
            base_utility.log("[client_tips_frame_view]get tip dlg id failed");
            return;
        end;

        -- 移动bubble tips
        local tip_data = client_tips_frame_model.get_normal_tip_by_id(tip_id);
        local tips_type_normal = 0;
        if tip_data ~= nil and tip_data.tips_type_normal ~= nil then
            tips_type_normal = tip_data.tips_type_normal;
        end;

        local is_close_dlg_in_corner = client_tips_frame_view.is_dlg_in_corner(dlg_id);

        --shadow_helper.destroy_shadow(dlg_id);
        client_tips_frame_view.close_tips_dlg(dlg_id,
                        client_tips_frame_model.normal_dlg_queue,
                        client_tips_frame_model.normal_tips_queue,
                        tip_wait.close_type);

        
        need_move_bubble, move_height = client_tips_frame_view.need_move_bubble_for_close_norm(tips_type_normal, is_close_dlg_in_corner);
        if need_move_bubble == true then
            -- 得到一个normal tip dlg id
            if move_height == 0 then
                move_height = temp_move_height;
            end;
            base_utility.log("[client_tips_frame_view][remove_normal_tip_in_tick]after close normal dlg, will move bubble tips, move_height=" .. move_height);
            move_height = move_height - client_tips_view_constant.BUBBLE_REDUCE_HEIGHT;
            client_tips_frame_view.move_bubble_tips_pos(false, move_height);
        end;
    end;

    -- 在定时器里面移除气泡tips窗口
    remove_bubble_tip_in_tick = function (tip_wait)
        local close_tip_id = tip_wait.tip_id;
        local dlg_id = client_tips_frame_model.get_bubble_tip_dlg_id(close_tip_id);
        local move_width = 0;
        local move_height = 0;
        if dlg_id ~= nil and dlg_id > 0 then
            move_width, move_height = ui_utility.get_control_size_by_id(dlg_id);
            move_height = move_height - client_tips_view_constant.BUBBLE_REDUCE_HEIGHT;
        else
            base_utility.log("[client_tips_frame_view] remove bubble, get bubble dlg id failed");
        end;

        -- 计算得到需要开始移动的气泡tip的起始tip_id
        local begin_move_tip_id = 0;
        for index = 1, (#(client_tips_frame_model.bubble_tips_queue) - 1) do
            local cur_tip_id = client_tips_frame_model.bubble_tips_queue[index].id;
            if close_tip_id == cur_tip_id then
                begin_move_tip_id = client_tips_frame_model.bubble_tips_queue[index + 1].id;
                break;
            end;
        end;
        -- 关闭窗口
        client_tips_frame_view.close_tips_dlg(dlg_id,
                        client_tips_frame_model.bubble_dlg_queue,
                        client_tips_frame_model.bubble_tips_queue,
                        tip_wait.close_type);

        -- 判断是否需要下移气泡tips
        local need_move_bubble = client_tips_frame_view.need_move_bubble_for_close_bubb(close_tip_id);

        if need_move_bubble == true then
            -- 倒序移动
            base_utility.log("[client_tips_frame_view] close bubble dlg, begin move other bubble tips");
            if begin_move_tip_id > 0 then
                -- 获得begin_move_tip_id所在的index
                local begin_index = 0;
                for index = 1, #(client_tips_frame_model.bubble_tips_queue) do
                    if client_tips_frame_model.bubble_tips_queue[index].id == begin_move_tip_id then
                        begin_index = index;
                        break;
                    end;
                end;
                -- 从begin_index开始移动气泡tips
                local end_index = #(client_tips_frame_model.bubble_tips_queue);
                for move_index = begin_index, end_index do
                    client_tips_frame_view.move_one_bubble_pos(move_index, move_height, false);
                end;
            end;
        else
            -- 最后一个tips，置为false
            client_tips_frame_control.is_closing_tip = false;
        end;

    end;

    -- 在定时器里面移除web tips窗口
    remove_web_tip_in_tick = function (tip_wait)
        -- body
    end;

    -- 关闭通用tips弹框
    -- dlg_id:待关闭窗口id;dlg_queue:窗口队列;tips_queue:tips队列; close_type:关闭类型
    close_tips_dlg = function (dlg_id, dlg_queue, tips_queue, close_type)
        local close_ret_data  = {};
        if dlg_id ~= nil and dlg_id > 0 then
            base_utility.log("[client_tips_frame_view][close_tips_dlg]remove tips dlg, dlg_id = ".. dlg_id);
            -- 关闭dlg的显示
            layout_mgr.delay_remove_ctrl(dlg_id);
            -- 移除model中存储的dlg信息
            local tips_id = 0;
            for key, value in pairs(dlg_queue) do
                if value == dlg_id then
                    tips_id = key;
                    dlg_queue[key] = nil;
                    break;
                end;
            end;
            -- 移除model中存储的tips信息
            local tips_remove_index = 0;
            for index = 1, #(tips_queue) do
                if tips_queue[index].id == tips_id then
                    tips_remove_index = index;
                    break;
                end;
            end;



            -- 准备关闭前的返回数据，用于关闭后告诉调用者
            if tips_queue[tips_remove_index].repeat_num ~= nil then
                -- 增加repeat_num后的id,还原出真实的id
                close_ret_data.id = tips_queue[tips_remove_index].id - tips_queue[tips_remove_index].id - tips_queue[tips_remove_index].repeat_num;
            else
                close_ret_data.id = tips_queue[tips_remove_index].id;
            end;
            
            close_ret_data.tips_main_type = tips_queue[tips_remove_index].tips_main_type;
            close_ret_data.tips_sub_type = tips_queue[tips_remove_index].tips_sub_type;

            close_ret_data.close_service = tips_queue[tips_remove_index].close_service;
            close_ret_data.close_type = close_type;
            if tips_queue[tips_remove_index].tips_plugin_id ~= nil then
                close_ret_data.tips_plugin_id = tips_queue[tips_remove_index].tips_plugin_id;
            end;

            if(tips_remove_index ~= 0) then
                table.remove(tips_queue, tips_remove_index);
            end;

            -- 关闭相关事件
        else
            base_utility.log("[client_tips_frame_view][close_tips_dlg] dlg_id is illegal");
        end;

        -- 发送广播，告知窗口关闭
        if close_ret_data ~= nil and close_ret_data.close_service ~= nil then
             base_utility.log("[client_tips_frame_view] send broadcast to close service");
            client_tips_frame_control.send_tips_broadcast(close_ret_data.close_service, close_ret_data);
        else
            base_utility.log("[client_tips_frame_view] close service is nil, not send back");
        end;
    end;

    -- 以下为通用函数

    -- 添加定时器
    add_show_tick = function (show_duration, tips_id, close_callback)
        base_utility.log("[client_tips_frame_view][add_show_tick] tip has show_duration, add a show tick, tip_id=" .. tips_id);
        local tpfui = base_utility.get_component_adapter("ITpf_ui",
            "ierd_tgp.tpf_ui.GetTPFUI();");
        if tpfui ~= nil then
            tpfui:AddInterval(close_callback, show_duration, tips_id);
        end;
    end;

    -- 批量移动气泡tips
    move_bubble_tips_pos = function(up, move_height)
        local bubble_tips_num = #(client_tips_frame_model.bubble_tips_queue);
        if bubble_tips_num == 0 then
            return;
        end;
        if up == true then
            for index = 1, bubble_tips_num do
                -- 从上往下，一个个将气泡tips向上移动
                client_tips_frame_view.move_one_bubble_pos(index, move_height, up);
            end;
        else
            for index = 1, bubble_tips_num do
                -- 从下往上，一个个将气泡tips向下移动
                client_tips_frame_view.move_one_bubble_pos(
                        (bubble_tips_num - index + 1), move_height, up);
            end;
        end;
        
    end;

    -- 移动单个气泡tips
    move_one_bubble_pos = function(index, move_height, up)
        local cur_bubble_tip_id = client_tips_frame_model.bubble_tips_queue[index].id;
        for temp_key, temp_value in pairs(client_tips_frame_model.bubble_dlg_queue) do
            if cur_bubble_tip_id == temp_key then
                local p_cur_bubble_tips = ui_utility.get_ctrl_ptr_by_id(temp_value);
                client_tips_frame_view.move_tips_to_final_pos(temp_value, p_cur_bubble_tips, move_height, up);
                break;
            end;
        end;
    end;

    -- 通用tips:从起始位置移动到目标位置
    move_tips_to_final_pos = function (dw_dlg_id, p_dlg, move_height, up)
        -- 如果有气泡tips，则将气泡tips，顶到上面去 -toadd
        if p_dlg == nil then
            base_utility.log("[client_tips_frame_view] move_tips_to_final_pos failed, dlg not exist ");
            return;
        end;
        local start_pos = POINT:new_local();
        local end_pos = POINT:new_local();
        local rect_dlg = p_dlg:GetRectEx(TRUE,TRUE);
        -- local dlg_width, dlg_height = ui_utility.get_control_size_by_id(dw_dlg_id);
        start_pos.x = rect_dlg.left;
        start_pos.y = rect_dlg.top;

        end_pos.x = rect_dlg.left;
        if up == true then
            end_pos.y = start_pos.y - move_height;
        else
            end_pos.y = start_pos.y + move_height;
        end;

        animation_utility.init(dw_dlg_id,
                    "Common_Tips_Move", animation_utility.ANI_TYPE.ANI_MOVE);
        
        animation_utility.move_animation(
            dw_dlg_id, start_pos, end_pos,
            client_tips_view_constant.TIPS_ANIMATION_FRAME, 0);
    end;

    set_rich_box_txt = function (dw_dlg, richbox_path, show_content)
        local p_txt = ui_utility.get_ctrl_ptr_by_path(
                                        dw_dlg,
                                        richbox_path);
        local int_richtextbox = "Tenio::IRichTextBox";
        local p_rich = tolua.cast(p_txt, int_richtextbox);
        if p_rich ~= nil then
            p_rich:Clear();
            p_rich:PushBackHtmlString(U8toCUIStr(show_content));
        else
            base_utility.log("[client_tips_frame_view]get rich txt editor ".. richbox_path.." failed");
        end;
        
    end;

    resize_max_width = function (text, max_width, auto, char_font)
        text = text or "";
        local auto_line = auto or "auto";
        if type(text) ~= "string" or text == "" or auto == "none" then
            -- 关闭自动调整行宽度
            base_utility.log("[client_tips_frame_view]resize_max_width: close auto_line, text: " .. tostring(text) .. ", auto: " ..tostring(auto));
            return max_width;
        end

        local char_width = char_font or 16; -- 默认为16号字体，宽度16
        local text_width = client_tips_frame_view.calc_u8text_width(text, char_font);

        local min_bound = 1.0 * char_width / max_width;
        local max_bound = 1 - 0.8 * char_width / max_width;
        local t1,t2 = math.modf(text_width/max_width);
        -- 保证最后一行有2个字符，并且最后一行不会很挤
        if t2 >= min_bound and t2 <= max_bound then
            -- 无需调整行宽度
            base_utility.log("[client_tips_frame_view]resize_max_width: no need to resize width:" 
                                .. "text_width:" .. text_width .. ", max_width:" .. max_width
                                .. ", auto_line:" .. auto .. ", char_font:" .. char_font); 
            return max_width;
        end

        local width;
        -- 先看扩长能否满足要求
        if auto == "auto" or auto == "wide" then
            for width = max_width + char_font, max_width + 2 * char_width, char_font do
                local t1,t2 = math.modf(text_width/width);
                if t2 >= min_bound and t2 <= max_bound then
                    base_utility.log("[client_tips_frame_view]resize_max_width: larger width: resize_width:" .. width  
                                        .. ", text_width:" .. text_width .. ", max_width:" .. max_width
                                        .. ", auto_line:" .. auto .. ", char_font:" .. char_font);
                    return width;
                end       
            end 
        end 

        -- 再看缩短能否满足要求
        if auto == "auto" or auto == "narrow" then
            for width = max_width - char_font, max_width - 2 * char_width, -char_font do
                local t1,t2 = math.modf(text_width/width);
                if t2 >= min_bound and t2 <= max_bound then
                    base_utility.log("[client_tips_frame_view]resize_max_width: narrow width: resize_width:" .. width  
                                        .. ", text_width:" .. text_width .. ", max_width:" .. max_width
                                        .. ", auto_line:" .. auto .. ", char_font:" .. char_font);
                    return width;
                end       
            end     
        end

        -- 无法满足要求
        base_utility.log("[client_tips_frame_view]resize_max_width: unable to resize width, text:" .. text 
                                .. ", text_width:" .. text_width .. ", max_width:" .. max_width
                                .. ", auto_line:" .. auto .. ", char_font:" .. char_font, true); 
        return max_width;
    end;

    calc_u8text_width = function (text, char_font)
        -- 计算utf-8字符长度
        base_utility.log("[client_tips_frame_view]calc_u8text_width, text: " .. text .. ", char_font: " .. char_font);
        local text_width = 0;
        if type(text) == "string" then
            local left = string.len(text);
            local arr  = {0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
            while left ~= 0 do
                local tmp = string.byte(text, -left);
                local i   = #arr;
                while arr[i] do
                    if tmp >= arr[i] then
                        left = left - i
                        break
                    end
                    i = i - 1
                end
                if i == 1 then 
                    -- 英文字符
                    text_width = text_width + char_font / 2;
                else 
                    -- 中文字符
                    text_width = text_width + char_font;
                end
            end
        else
            base_utility.log("[client_tips_frame_view]calc_u8text_width, not string input: " .. tostring(text), true);
        end
        base_utility.log("[client_tips_frame_view]calc_u8text_width, text_width: " .. text_width);
        return text_width;
                
    end;

    set_normal_tip_content_width = function (dw_dlg, tip_data, width_no_icon, width_width_icon)
        local width = 0;
        if tip_data ~= nil and tip_data.tips_icon ~= nil then
            width = width_width_icon;
        else
            width = width_no_icon;
        end;
        -- 大tips才支持自动调整间距大小
        if tip_data ~= nil and tip_data.tips_type_normal ~= nil and tip_data.tips_type_normal == 1 then
            -- 根据副标题大小确定文本宽度, 副标题字体宽度为12
            width = client_tips_frame_view.resize_max_width(tip_data.sub_title, width, "auto", 12);
        end
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_main_type_father, "Width", width);
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "Width", width);
    end;

    set_normal_maintitle_pos = function (dw_dlg, has_subtitle, has_icon)
        local p_txt = nil;
        local richbox_path = client_tips_res.txt_main_type;
        local richbox_path_big = client_tips_res.txt_main_type_big;
        local richbox_path_father = client_tips_res.txt_main_type_father;
        if has_subtitle == true then
            p_txt = ui_utility.get_ctrl_ptr_by_path(
                                        dw_dlg,
                                        richbox_path);
        else
            p_txt = ui_utility.get_ctrl_ptr_by_path(
                                        dw_dlg,
                                        richbox_path_big);
        end;
        local int_richtextbox = "Tenio::IRichTextBox";
        local p_rich = tolua.cast(p_txt, int_richtextbox);
        if p_rich ~= nil then
            local row_count = p_rich:GetRowCount();
            if row_count == 1 then
                -- 设置高度
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "Height", "20");
            elseif row_count >= 2 then
                -- 设置高度
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "Height", "40");
            end;
            if has_subtitle then
                -- 有副标题
                ui_utility.setproperty_by_path(dw_dlg, richbox_path, "Visible", "true");
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_big, "Visible", "false");
                if row_count == 1 then
                    ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "YOffset", "12");
                else
                    ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "YOffset", "0");
                end;
            else
                -- 没有副标题
                ui_utility.setproperty_by_path(dw_dlg, richbox_path, "Visible", "false");
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_big, "Visible", "true");

                if row_count == 1 then
                    ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "YOffset", "20");
                else
                    ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "YOffset", "10");
                end;
            end;
            if has_icon == false then
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "XOffset", "28");
            end;
            
        else
            base_utility.log("[client_tips_frame_view]get rich txt editor ".. richbox_path.." failed");
        end;
    end;

    set_normal_subtitle_pos = function (dw_dlg, has_maintitle, has_icon)
        if has_maintitle == true then
            -- 有主标题的话，判断主标题的行数
            local p_txt = ui_utility.get_ctrl_ptr_by_path(
                                        dw_dlg,
                                        client_tips_res.txt_main_type);
            local int_richtextbox = "Tenio::IRichTextBox";
            local p_rich = tolua.cast(p_txt, int_richtextbox);
            if p_rich ~= nil then
                local row_count = p_rich:GetRowCount();
                if row_count == 1 then
                    -- 只有一行
                    ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "YOffset", "33");
                else
                    ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "YOffset", "42");
                end;
            end;
        else
            -- 没有主标题，则居中
            ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "YOffset", "23");
        end;
        if has_icon == false then
            ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "XOffset", "28");
        end;
        
    end;

    set_bubble_maintitle_pos = function (dw_dlg, tips_data)
        local width = 220;
        local xoffset = 0;
        local yoffset_maintitle = 0;
        local yoffset_subtitle = 0;
        local yoffset_thirdtitle = 0;
        if tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 1 then
            -- 长图
            if tips_data.tips_icon ~= nil then
                width = 220;
                xoffset = 0;
            else
                xoffset = 15;
                width = 285;
            end;
            if tips_data.sub_title == nil and tips_data.third_title == nil then
                -- 只有主标题,设置位置
                yoffset_maintitle = 11;
                yoffset_subtitle = 36;
                yoffset_thirdtitle = 58;
            else
                yoffset_maintitle = 0;
                yoffset_subtitle = 36;
                yoffset_thirdtitle = 58;
            end;
        else
            if tips_data.tips_icon ~= nil then
                width = 220;
                xoffset = 0;
            else
                width = 284;
                xoffset = 15;
            end;
            if tips_data.sub_title == nil and tips_data.third_title == nil then
                -- 只有主标题,设置位置
                yoffset_maintitle = 11;
                yoffset_subtitle = 24;
                yoffset_thirdtitle = 44;
            elseif tips_data.sub_title ~= nil and tips_data.third_title ~= nil then
                yoffset_maintitle = -2;
                yoffset_subtitle = 18;
                yoffset_thirdtitle = 34;
            else
                yoffset_maintitle = 5;
                yoffset_subtitle = 30;
                yoffset_thirdtitle = 30;
            end;
        end;
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_main_father, "Width", tostring(width));
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_sub_father, "Width", tostring(width));
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_main_father, "YOffset", tostring(yoffset_maintitle));
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_sub_father, "YOffset", tostring(yoffset_subtitle));
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_main_father, "XOffset", tostring(xoffset));
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_sub_father, "XOffset", tostring(xoffset));
        -- if tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 1 then
            
        -- end;
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_third_father, "Width", tostring(width));
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_third_father, "YOffset", tostring(yoffset_thirdtitle));
        ui_utility.setproperty_by_path(dw_dlg, client_tips_res.bubble_txt_third_father, "XOffset", tostring(xoffset));
    end;

    set_bubble_resp_btn = function (dw_bubble_dlg_id, tips_data)
        local has_other_click = false;

        if tips_data.win_click_url ~= nil then
            has_other_click = true;
        end

        if tips_data.main_title_url ~= nil then
            has_other_click = true;
        end;

        if tips_data.sub_title_url ~= nil then
            has_other_click = true;
        end;

        if tips_data.third_title_url ~= nil then
            has_other_click = true;
        end;

        if has_other_click == false then
            -- 设置响应按钮是否可以响应
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_tips_all_btn, "Visible", "false");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_main_btn, "Visible", "false");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_sub_btn, "Visible", "false");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_third_btn, "Visible", "false");
        else
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_tips_all_btn, "Visible", "true");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_main_btn, "Visible", "true");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_sub_btn, "Visible", "true");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_third_btn, "Visible", "true");
        end;

        if tips_data.tips_type_bubble ~= nil and tips_data.tips_type_bubble == 2 then
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_tips_all_btn, "Visible", "false");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_main_btn, "Visible", "false");
            ui_utility.setproperty_by_path(dw_bubble_dlg_id, client_tips_res.bubble_txt_sub_btn, "Visible", "false");
        end
    end;

    set_normal_pic_btn = function (dw_normal_dlg_id, tips_data)
        if nil ~= tips_data.icon_click_url and "" ~= tips_data.icon_click_url then
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.nor_img_click, "Visible", "true");
        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.nor_img_click, "Visible", "false");
        end
    end;

    set_normal_resp_btn = function (dw_normal_dlg_id, tips_data)
        if tips_data.main_title_url ~= nil then
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.txt_main_type_btn, "Visible", "false");
        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.txt_main_type_btn, "Visible", "true");
        end;

        if tips_data.sub_title_url ~= nil then
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.txt_sub_type_btn, "Visible", "false");
        else
            ui_utility.setproperty_by_path(dw_normal_dlg_id, client_tips_res.txt_sub_type_btn, "Visible", "true");
        end;

    end;

    set_normal_big_maintitle_pos = function (dw_dlg, has_subtitle, has_icon)
        local p_txt = nil;
        local richbox_path = client_tips_res.txt_main_type;
        local richbox_path_father = client_tips_res.txt_main_type_father;
        p_txt = ui_utility.get_ctrl_ptr_by_path(
                    dw_dlg,
                    richbox_path);
        local int_richtextbox = "Tenio::IRichTextBox";
        local p_rich = tolua.cast(p_txt, int_richtextbox);
        if p_rich ~= nil then
            if has_subtitle then
                -- 有副标题
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "YOffset", "0");
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "Height", "20");
            else
                -- 没有副标题
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "YOffset", "17");
                ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "Height", "40");
            end;
        else
            base_utility.log("[client_tips_frame_view]get rich txt editor ".. richbox_path.." failed");
        end;
        if has_icon == false then
            ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "XOffset", "23");
        else
            ui_utility.setproperty_by_path(dw_dlg, richbox_path_father, "XOffset", "0");
        end;
    end;

    set_normal_big_subtitle_pos = function (dw_dlg, has_maintitle, has_icon)
        if has_maintitle == true then
            ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "YOffset", "25");
        else
            -- 没有主标题，则居中
            ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "YOffset", "17");
        end;
        if has_icon == false then
            ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "XOffset", "23");
        else
            ui_utility.setproperty_by_path(dw_dlg, client_tips_res.txt_sub_type_father, "XOffset", "0");
        end;
    end;

    -- backgrounded tips
    show_bkd_tips = function(params)

        if base_utility.is_type_of_oversea_ver() then
            return;
        end

        local delay_showed = false;
        local params_tbl = params;
        if type(params) == "number" then --game id, called from timer callback
            params_tbl = client_tips_frame_model.get_app_exit_config(params);
            base_utility.remove_interval("client_tips_frame_view.show_bkd_tips", params);
            delay_showed = true;
        end

        if type(params_tbl) ~= "table" then
            return;
        end

        base_utility.log(
            "[client_tips_frame_view]show bkd tips: ".. base_utility.table_to_json(params_tbl));

        if client_tips_frame_model.is_app_exit_tips_showing(params_tbl.game_id) then
            return;
        end;

        local show_remind_in_days_ctrl = true;
        if nil ~= params_tbl.show_remind_in_days and 
            0 == tonumber(params_tbl.show_remind_in_days) then
            show_remind_in_days_ctrl = false;
        end

        if show_remind_in_days_ctrl then --check last show time
            local config_local = client_tips_frame_model.get_app_exit_local_config(params_tbl.game_id);
            if nil ~= config_local and nil ~= config_local.value then
                local config_local_tbl = base_utility.json_to_table(config_local.value);
                if nil ~= config_local_tbl and nil ~= config_local_tbl.last_show_time then
                    local duration = os.difftime(os.time(), config_local_tbl.last_show_time);
                    if duration < 7 * 24 * 60 * 60 then
                        base_utility.log( "[client_tips_frame_view]bkd tips showed last time");
                        return;
                    end
                end
            end
        end

        if not delay_showed and
            nil ~= params_tbl.delay_show and 
                "" ~= params_tbl.delay_show and
                    tonumber(params_tbl.delay_show) > 0 then
            base_utility.add_interval("client_tips_frame_view.show_bkd_tips"
                        , tonumber(params_tbl.delay_show) * 1000, tonumber(params_tbl.game_id));
            return;
        end

        local tips_dlg = layout_mgr.restore_layout_multi(client_tips_res.tpf_app_bkd_tips);
        if 0 == tips_dlg then
            base_utility.log("[client_tips_frame_view]bkd tips dlg id invalid", true);
            return
        end

        local tips_dlg_ptr = ui_utility.get_ctrl_ptr_by_id(tips_dlg);
        if nil == tips_dlg_ptr then
            base_utility.log("[client_tips_frame_view]bkd tips dlg handle invalid", true);
            return
        end

        client_tips_frame_model.add_dlg_to_app_exit_config(tips_dlg, params_tbl);

        -- tips dialog position
        client_tips_frame_view.set_bkd_tips_position(tips_dlg, tips_dlg_ptr);

        -- background
        if nil ~= params_tbl.background_url and "" ~= params_tbl.background_url then
            local bk_url = "ONEIMAGE:client_tips\\popup_bk.png|"..params_tbl.background_url..";Center;0;"
            ui_utility.setproperty_by_id(tips_dlg, "Background", bk_url);
        end

        if not show_remind_in_days_ctrl then
            local cbx_ctrl = ui_utility.get_ctrl_id_by_path(tips_dlg, "title_bar\\cbx_remind_in_days");
            ui_utility.setproperty_by_id(cbx_ctrl, "Visible", "false");
        end

        if nil == params_tbl.url or "" == params_tbl.url then
            local bk_btn_ctrl = ui_utility.get_ctrl_id_by_path(tips_dlg, "background_btn");
            ui_utility.setproperty_by_id(bk_btn_ctrl, "Visible", "false");
        end

        tips_dlg_ptr:Show(TRUE);

        if client_tips_frame_model.is_game_running == false then
            tips_dlg_ptr:BringToTop();
        end;

        local show_timeout = 0;
        if nil ~= params_tbl.auto_close and "" ~= params_tbl.auto_close then
            show_timeout = tonumber(params_tbl.auto_close);
        end
        if show_timeout > 0 then
            base_utility.add_interval("client_tips_frame_view.close_bkd_tips_dlg_timeout"
                        , show_timeout * 1000, tips_dlg);
        end

        client_tips_frame_control.report_bkd_tips_operation(params_tbl.game_id
                                , app_exit_tips_actions.kAppExitTipsShow);

    end;

    set_bkd_tips_position = function(dlg_id, dlg_ptr)
        local tpf_ui = base_utility.get_component_adapter("ITpf_ui", "ierd_tgp.tpf_ui.GetTPFUI();");
        if nil == tpf_ui then
            return;
        end
        local sys_param = ierd_tgp.tpf_ui.SysParams:new();
        tpf_ui:get_sys_params(sys_param);
        local work_area_width = sys_param.work_area_width;
        local work_area_height = sys_param.work_area_height;
        local dlg_width, dlg_height = ui_utility.get_control_size_by_id(dlg_id);
        sys_param:delete();
        local rect_dlg = dlg_ptr:GetRectEx(TRUE,TRUE);
        rect_dlg.left = work_area_width - dlg_width - client_tips_view_constant.TIPS_INTERVAL;
        rect_dlg.top = work_area_height - dlg_height - client_tips_view_constant.TIPS_INTERVAL;
        rect_dlg.right = rect_dlg.left + dlg_width;
        rect_dlg.bottom = rect_dlg.top + dlg_height;
        dlg_ptr:MoveEx(rect_dlg,TRUE);
    end;

    close_bkd_tips_dlg = function(dlg_id)
        layout_mgr.delay_remove_ctrl(dlg_id);
        local cfg = client_tips_frame_model.get_app_exit_config_by_dlg(dlg_id);
        if nil ~= cfg and nil ~= cfg.game_id then
            client_tips_frame_control.report_bkd_tips_operation(cfg.game_id
                                , app_exit_tips_actions.kAppExitTipsCloseActive);
        end
        client_tips_frame_model.add_dlg_to_app_exit_config(dlg_id, nil);
    end;

    close_bkd_tips_dlg_timeout = function(dlg_id)
        layout_mgr.delay_remove_ctrl(dlg_id);
        base_utility.remove_interval("client_tips_frame_view.close_bkd_tips_dlg_timeout", dlg_id);
        local cfg = client_tips_frame_model.get_app_exit_config_by_dlg(dlg_id);
        if nil ~= cfg and nil ~= cfg.game_id then
            client_tips_frame_control.report_bkd_tips_operation(cfg.game_id
                                , app_exit_tips_actions.kAppExitTipsClosePassive);
        end
        client_tips_frame_model.add_dlg_to_app_exit_config(dlg_id, nil);
    end;

    click_bkd_tips_background = function(dlg_id)
        local config = client_tips_frame_model.get_app_exit_config_by_dlg(dlg_id);
        if nil ~= config and nil ~= config.url and "" ~= config.url then
            local param = { 
                type = "open_web", 
                browser = "new", 
                use_ptlogin = 1, 
                url = config.url
            };
            comm_center.call_service("i_service_open_link_confirm_launch", param);
            if nil ~= config.game_id then
                client_tips_frame_control.report_bkd_tips_operation(config.game_id
                                    , app_exit_tips_actions.kAppExitTipsClick);
            end
        end
    end;

    on_local_web_loaded = function(win_id, opts)
        base_utility.log("[client_tips_frame_view]on_local_web_loaded, " .. tostring(win_id));
        client_tips_frame_view.show_bubble_tips_impl(win_id, opts);
    end;
}